package cn.blnp.net.flowable.boot.utils;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;

/**
 * <h3>动态创建流程模型工具类</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/6/19 11:06
 */
@Slf4j
@AllArgsConstructor
public class DynamicProcessCreateUtil {

    private RepositoryService repositoryService;
    private BpmnModel model;
    private Process process;

    /**
     * <p><b>用途:创建流程<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 11:10 2025/6/19
     * @params [processKey, processName]
     * @param processKey 流程Key
     * @param processName 流程名称
     * @return void
    **/
    public void createProcess(String processKey, String processName) {
        this.model.addProcess(process);
        this.process.setId(processKey);
        this.process.setName(processName);
    }

    /**
     * <p><b>用途:创建开始节点<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 11:13 2025/6/19
     * @params [id, name]
     * @param id 节点编号
     * @param name 节点名称
     * @return org.flowable.bpmn.model.StartEvent
    **/
    public StartEvent createStartEvent(String id, String name) {
        StartEvent startEvent = new StartEvent();
        startEvent.setId(id);
        startEvent.setName(name);
        this.process.addFlowElement(startEvent);
        return startEvent;
    }

    /**
     * <p><b>用途:创建结束节点<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 11:14 2025/6/19
     * @params [id, name]
     * @param id 节点编号
     * @param name 节点名称
     * @return org.flowable.bpmn.model.EndEvent
    **/
    public EndEvent createEndEvent(String id, String name) {
        EndEvent endEvent = new EndEvent();
        endEvent.setId(id);
        endEvent.setName(name);
        this.process.addFlowElement(endEvent);
        return endEvent;
    }

    /**
     * <p><b>用途:创建用户任务<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 11:15 2025/6/19
     * @params [id, name, assignee]
     * @param id 节点编号
     * @param name
     * @param assignee
     * @return org.flowable.bpmn.model.UserTask
    **/
    public UserTask createUserTask(String id, String name, String assignee) {
        UserTask userTask = new UserTask();
        userTask.setName(name);
        userTask.setId(id);
        userTask.setAssignee(assignee);
        this.process.addFlowElement(userTask);
        return userTask;
    }

    /**
     * <p><b>用途:创建排他网关<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 11:54 2025/6/19
     * @params [id, name]
     * @param id 节点编号
     * @param name 节点名称
     * @return org.flowable.bpmn.model.ExclusiveGateway
    **/
    public ExclusiveGateway createExclusiveGateway(String id, String name) {
        ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
        exclusiveGateway.setId(id);
        exclusiveGateway.setName(name);
        this.process.addFlowElement(exclusiveGateway);
        return exclusiveGateway;
    }

    /**
     * <p><b>用途:创建顺序流<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 11:55 2025/6/19
     * @params [from, to]
     * @param from 起始节点编号
     * @param to 目标节点编号
     * @return org.flowable.bpmn.model.SequenceFlow
    **/
    public SequenceFlow createSequenceFlow(String from, String to) {
        SequenceFlow flow = new SequenceFlow();
        flow.setSourceRef(from);
        flow.setTargetRef(to);
        this.process.addFlowElement(flow);
        return flow;
    }

    /**
     * <p><b>用途:创建带条件顺序流<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 11:55 2025/6/19
     * @params [from, to, conditionExpression]
     * @param from 起始节点编号
     * @param to 模板节点编号
     * @param conditionExpression 条件
     * @return org.flowable.bpmn.model.SequenceFlow
    **/
    public SequenceFlow createSequenceFlow(String from, String to, String conditionExpression) {
        SequenceFlow flow = new SequenceFlow();
        flow.setSourceRef(from);
        flow.setTargetRef(to);
        flow.setConditionExpression(conditionExpression);
        this.process.addFlowElement(flow);
        return flow;
    }

    /**
     * <p><b>用途:生成bpmn自动布局<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 13:35 2025/6/19
     * @params [] 
     * @param  
     * @return void
    **/
    public void autoLayout() {
        BpmnAutoLayout layout = new BpmnAutoLayout(model);
        layout.execute();
    }

    /**
     * <p><b>用途:部署当前流程<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 13:35 2025/6/19
     * @params [] 
     * @param  
     * @return org.flowable.engine.repository.ProcessDefinition
    **/
    public ProcessDefinition deployProcess() {
        Deployment deployment = repositoryService.createDeployment()
                .addBpmnModel(process.getId() + ".bpmn", model)
                .name(process.getName()).deploy();
        ProcessDefinition processDefinition = repositoryService
                .createProcessDefinitionQuery()
                .deploymentId(deployment.getId()).singleResult();
        return processDefinition;
    }
}
